package com.atguigu.gmall.order.service.impl;
import java.util.Date;

import java.util.*;
import java.math.BigDecimal;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.atguigu.gmall.common.constants.RabbitMqConst;
import com.atguigu.gmall.common.constants.RedisConst;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.JsonUtil;
import com.atguigu.gmall.common.util.UserAuthToUtil;
import com.atguigu.gmall.feign.cart.CartFeignClient;
import com.atguigu.gmall.feign.pay.PayFeignClient;
import com.atguigu.gmall.feign.product.ProductFeignClient;
import com.atguigu.gmall.feign.user.UserFeignClient;
import com.atguigu.gmall.feign.ware.WareFeiClient;
import com.atguigu.gmall.model.cart.CartItem;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.model.to.UserAuthTo;
import com.atguigu.gmall.model.to.order.OrderCreateTo;
import com.atguigu.gmall.model.to.ware.WareDetailsTo;
import com.atguigu.gmall.model.to.ware.WareOrderTo;
import com.atguigu.gmall.model.to.ware.WareSkuVo;
import com.atguigu.gmall.model.to.ware.WareSplitVo;
import com.atguigu.gmall.model.user.UserAddress;
import com.atguigu.gmall.model.vo.order.CartItemForOrderVo;
import com.atguigu.gmall.model.vo.order.OrderSubmitVo;
import com.atguigu.gmall.order.service.OrderDetailService;
import com.atguigu.gmall.order.service.OrderInfoService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;

import com.atguigu.gmall.model.vo.order.OrderConfirmVo;
import com.atguigu.gmall.order.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

/**
 * @author A
 * @version 1.0
 * @description: TODO
 * @date 2024/10/7 9:03
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    CartFeignClient cartFeignClient;
    @Autowired
    ProductFeignClient productFeignClient;
    @Autowired
    UserFeignClient userFeignClient;
    @Autowired
    WareFeiClient wareFeiClient;
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    OrderInfoService orderInfoService;
    @Autowired
    OrderDetailService orderDetailService;
    @Qualifier("otherPool")
    @Autowired
    ThreadPoolExecutor otherPool;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    PayFeignClient payFeignClient;
    /**
     * @description:返回订单确认页数据
     * @author: chensiwei
     * @date: 2024/10/7 9:25
     * @param: []
     * @return: com.atguigu.gmall.model.vo.order.OrderConfirmVo
     **/
    @Override
    public OrderConfirmVo getCartConfirmList() {
        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();

        //远程调用cart服务
        Result<List<CartItem>> itemForOrderVo = cartFeignClient.getCartItemForOrderVo();
        if (itemForOrderVo.isOk()) {
            //选中的购物车项
            List<CartItem> cartItems = itemForOrderVo.getData();
            List<CartItemForOrderVo> collect = cartItems.stream().map(cartItem -> {
                CartItemForOrderVo cartItemForOrderVo = new CartItemForOrderVo();
                cartItemForOrderVo.setImgUrl(cartItem.getSkuDefaultImg());
                cartItemForOrderVo.setSkuName(cartItem.getSkuName());
                //远程调用实时价格
                Result<BigDecimal> price = productFeignClient.getPrice(cartItem.getSkuId());
                cartItemForOrderVo.setOrderPrice(price.getData());
                cartItemForOrderVo.setSkuNum(cartItem.getSkuNum());
                //查询是否有库存 远程调用库存服务
                String stock = wareFeiClient.hasStock(cartItem.getSkuId(), cartItem.getSkuNum());
                cartItemForOrderVo.setStock(stock);
                return cartItemForOrderVo;
            }).collect(Collectors.toList());
            orderConfirmVo.setDetailArrayList(collect);

            Integer totalNum = cartItems.stream().map(CartItem::getSkuNum).reduce(Integer::sum).get();
            orderConfirmVo.setTotalNum(totalNum);
            //实时总价格
            BigDecimal totalAmount = collect.stream().map(cartItem -> {
                return cartItem.getOrderPrice().multiply(BigDecimal.valueOf(cartItem.getSkuNum()));
            }).reduce(BigDecimal::add).get();

            orderConfirmVo.setTotalAmount(totalAmount);
        }

        //远程调用user服务
        Result<List<UserAddress>> userAddressList = userFeignClient.getUserAddressList();
        if (userAddressList.isOk()) {
            orderConfirmVo.setUserAddressList(userAddressList.getData());
        }
        //生产防重复提交交易号
        String token = generateToken();
        orderConfirmVo.setTradeNo(token);

        return orderConfirmVo;
    }

    //检查是否重复提交
    public Boolean checkToken(String token) {
        //1、原子验令牌+删令牌
        String script = "if redis.call('get', KEYS[1]) == '1' then return redis.call('del', KEYS[1]) else return 0 end";
        Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(RedisConst.NO_COMPEAT_TOKEN + token), "1");
        return result == 1L;
    }

    //生产防重复提交token
    public String generateToken() {
        String token = UUID.randomUUID().toString().replace("-", "");
        //在redis中存一份;每个rediskey都应该有过期时间
        redisTemplate.opsForValue().set(RedisConst.NO_COMPEAT_TOKEN + token, "1", 10L, TimeUnit.MINUTES);

        return token;

    }

    //保存订单

    @Override
    public Long submitOrder(String tradeNo, OrderSubmitVo orderSubmitVo) {
        //验证令牌
        Boolean checkToken = checkToken(tradeNo);
        if (!checkToken) {
            //令牌不相同,抛出异常
            throw new GmallException(ResultCodeEnum.NOREPEAT_TOKEN_ERROR);
        }
        //令牌相同,走下面逻辑

        //验证价格
        List<CartItemForOrderVo> orderDetailList = orderSubmitVo.getOrderDetailList();
        //查总价是否一致
        BigDecimal submitPrice = orderDetailList.stream().map(cartItem -> {
            BigDecimal multiply = cartItem.getOrderPrice().multiply(BigDecimal.valueOf(cartItem.getSkuNum()));
            return multiply;
        }).reduce(BigDecimal::add).get();
        //查询数据库价格(远程调用cart服务,返回选中的购物车项列表)
        Result<List<CartItem>> item = cartFeignClient.getCartItemForOrderVo();
        List<CartItem> cartItems = item.getData();
        BigDecimal currentPrice = cartItems.stream().map(cartItem -> {
            BigDecimal multiply = productFeignClient.getPrice(cartItem.getSkuId()).getData().multiply(BigDecimal.valueOf(cartItem.getSkuNum()));
            return multiply;
        }).reduce(BigDecimal::add).get();
        if (submitPrice.compareTo(currentPrice) != 0) {
            //提交价格和实时价格不相同
            throw new GmallException(ResultCodeEnum.ORDER_PRICE_CHANGE);
        }
        //验证库存
        List<String> str = new ArrayList<>();
        cartItems.stream().forEach(cartItem -> {
            String stock = wareFeiClient.hasStock(cartItem.getSkuId(), cartItem.getSkuNum());
            if (stock.equals("0")) {
                //没有库存
                str.add("[" + cartItem.getSkuName() + ":没有库存]");
            }
        });
        if (str.size() > 0) {
            //表明至少有一项没库存
            String msg = str.stream().reduce((a, b) -> {
                return a + "," + b;
            }).get();
            GmallException exception = new GmallException(msg, ResultCodeEnum.PRODUCT_NO_STOCK.getCode());
            throw exception;
        }

        //锁库存


        //生成订单保存(并向延迟队列发送关单消息,延迟30min)
        Long orderId = saveOrder(orderSubmitVo);
        RequestAttributes oldRequest = RequestContextHolder.getRequestAttributes();
        //删除购物车中选中的项
        otherPool.submit(()->{
            log.info("正在删除购物车");
            try {
                //线程池当前线程
                RequestContextHolder.setRequestAttributes(oldRequest);
                cartFeignClient.deleteChecked();
            } catch (Exception e) {
                log.error("删除购物车异常:{}",e);
            }
        });

        return orderId;

    }
    @Transactional
    @Override
    public Long saveOrder(OrderSubmitVo orderSubmitVo) {
        OrderInfo orderInfo = prepareOrderInfo(orderSubmitVo);
        //保存orderInfo
        orderInfoService.save(orderInfo);

        //保存order_detail
        List<OrderDetail> orderDetailList = prepareOrderDetailList(orderInfo);
        orderDetailService.saveBatch(orderDetailList);
        Long orderInfoId = orderInfo.getId();
        //向rabbitmq发送关单消息
        sendOrderCreateMsg(orderInfoId);
        return orderInfoId;
    }

    @Override
    public void checkOrderStatus(String outTradeNo) {
        String userIdStr = outTradeNo.split("-")[2];
        Long userId = Long.valueOf(userIdStr);
        LambdaQueryWrapper<OrderInfo> queryWrapper = Wrappers.lambdaQuery(OrderInfo.class)
                .eq(OrderInfo::getUserId, userId)
                .eq(OrderInfo::getOutTradeNo, outTradeNo);

        OrderInfo orderInfo = orderInfoService.getOne(queryWrapper);
        //添加请求头,因为是mq通知,请求头没有userId字段
//        HttpServletRequestSetHeader(userId);
//        //远程调用支付宝信息(因为mq,请求头会丢失)
//        Result<String> orderStatus = payFeignClient.getOrderStatus(outTradeNo);
//        "TRADE_SUCCESS".equals(orderStatus.getData())&&

        if ((orderInfo.getOrderStatus().equals(OrderStatus.UNPAID.name())||orderInfo.getOrderStatus().equals(OrderStatus.CLOSED.name()))){
            orderInfoService.updateStatusToPaid(outTradeNo);
        }


    }
    //根据仓库id拆单,并存储
    @Override
    public List<WareOrderTo> OrderSplit(WareSplitVo wareSplitVo) {
        Long orderId = wareSplitVo.getOrderId();

        List<WareSkuVo> wareSkuMap = wareSplitVo.getWareSkuMap();
        OrderInfo orderInfo = orderInfoService.getById(orderId);
        Long userId = orderInfo.getUserId();
        List<WareOrderTo> wareOrderToList =new ArrayList<>();
        //根据仓库id遍历,拆开的子订单存回库中
        wareSkuMap.stream().forEach(wareSkuVo -> {
            String wareId = wareSkuVo.getWareId();
            WareOrderTo wareOrderTo = new WareOrderTo();

            wareOrderTo.setConsignee(orderInfo.getConsignee());
            wareOrderTo.setConsigneeTel(orderInfo.getConsigneeTel());
            wareOrderTo.setOrderComment(orderInfo.getOrderComment());
            wareOrderTo.setOrderBody(orderInfo.getTradeBody());
            wareOrderTo.setDeliveryAddress(orderInfo.getDeliveryAddress());
            wareOrderTo.setPaymentWay(orderInfo.getPaymentWay());
            //仓库id
            wareOrderTo.setWareId(wareId);
            List<String> skuIds = wareSkuVo.getSkuIds();
            //子订单的订单项集合
            List<OrderDetail> childOrderDetails=new ArrayList<>();
            List<WareDetailsTo> wareDetailsTos=new ArrayList<>();
            skuIds.stream().forEach((skuId)->{
                LambdaQueryWrapper<OrderDetail> queryWrapper = Wrappers.lambdaQuery(OrderDetail.class)
                        .eq(OrderDetail::getOrderId, orderId)
                        .eq(OrderDetail::getSkuId, Long.valueOf(skuId));
                //订单项
                OrderDetail orderDetail = orderDetailService.getOne(queryWrapper);
                childOrderDetails.add(orderDetail);
                WareDetailsTo wareDetailsTo = new WareDetailsTo();
                wareDetailsTo.setSkuId(Long.valueOf(skuId));
                wareDetailsTo.setSkuNum(orderDetail.getSkuNum());
                wareDetailsTo.setSkuName(orderDetail.getSkuName());
                wareDetailsTos.add(wareDetailsTo);
            });
            wareOrderTo.setDetails(wareDetailsTos);


            //保存子订单和子订单项
            Long childId= saveChildOrderAndChildDetails(orderInfo, wareId,childOrderDetails);
            //订单id是保存回库中的子订单id
            wareOrderTo.setOrderId(childId);
            wareOrderToList.add(wareOrderTo);


        });
        //将订单状态改为已拆分
        orderInfoService.updateOrderStatusToSpilt(orderId,userId,ProcessStatus.SPLIT);
        return wareOrderToList;
    }
    //根据库存结果更改子订单状态
    @Override
    public void updateStatusByStock(Long orderId, ProcessStatus newProcessStatus) {
        orderInfoService.updateStatusByStock(orderId,newProcessStatus);
    }

    //保存子订单.返回子订单id
    private Long saveChildOrderAndChildDetails(OrderInfo parent, String wareId, List<OrderDetail> childOrderDetails) {
        //id自增
        OrderInfo childOrder = new OrderInfo();
        childOrder.setConsignee(parent.getConsignee());
        childOrder.setConsigneeTel(parent.getConsigneeTel());

        childOrder.setOrderStatus(parent.getOrderStatus());
        childOrder.setUserId(parent.getUserId());
        childOrder.setPaymentWay(parent.getPaymentWay());
        childOrder.setDeliveryAddress(parent.getDeliveryAddress());
        childOrder.setOrderComment(parent.getOrderComment());
        childOrder.setOutTradeNo(parent.getOutTradeNo());

        childOrder.setCreateTime(new Date());
        childOrder.setExpireTime(parent.getExpireTime());
        childOrder.setProcessStatus(parent.getProcessStatus());
        childOrder.setTrackingNo("");
        childOrder.setParentOrderId(parent.getId());

        childOrder.setWareId(wareId);
        childOrder.setProvinceId(parent.getProvinceId());
        childOrder.setRefundableTime(parent.getRefundableTime());
        //运费0
        childOrder.setFeightFee(new BigDecimal("0"));

        childOrder.setOperateTime(new Date());

        //设置list,顺便求总额
        childOrder.setOrderDetailList(childOrderDetails);
        childOrder.sumTotalAmount();
        //第一个skuId的商品
        childOrder.setTradeBody(childOrderDetails.get(0).toString());
        //第一个skuId的图片
        childOrder.setImgUrl(childOrderDetails.get(0).getImgUrl());
        //保存子订单
        orderInfoService.save(childOrder);
        //子订单自增id
        Long childOrderId = childOrder.getId();
        //保存子订单的子订单项
        childOrderDetails.stream().forEach(orderDetail -> {
            //回填子订单id
            orderDetail.setOrderId(childOrderId);
        });
        orderDetailService.saveBatch(childOrderDetails);
        return childOrderId;
    }
    //添加请求头
//    private static void HttpServletRequestSetHeader(Long userId) {
//        ServletRequestAttributes oldReq = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//        HttpServletRequest request = oldReq.getRequest();
//        String userId1 = request.getHeader("userId");
//        if (userId1==null){
//            Map<String, String> map = new HashMap<>();
//            map.put("userId", userId.toString());
//            HttpRequestUtil.setHeaders(request,map);
//        }
//    }

    //向延迟队列发送消息
    private void sendOrderCreateMsg(Long orderInfoId) {
        UserAuthTo userAuthTo = UserAuthToUtil.getUserAuthTo();
        OrderCreateTo orderCreateTo = new OrderCreateTo();
        orderCreateTo.setOrderId(orderInfoId);
        orderCreateTo.setUserId(userAuthTo.getUserId());

        rabbitTemplate.convertAndSend(RabbitMqConst.ORDER_EVENT_EXCHANGE,RabbitMqConst.ORDER_RK_CREATE,JsonUtil.obj2Json(orderCreateTo));
    }

    private List<OrderDetail> prepareOrderDetailList(OrderInfo orderInfo) {
        Long userId = UserAuthToUtil.getUserAuthTo().getUserId();
        //选中的购物车项
        List<CartItem> cartItems = cartFeignClient.getCartItemForOrderVo().getData();
        List<OrderDetail> orderDetailList = cartItems.stream().map(cartItem -> {
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setUserId(userId);
            orderDetail.setOrderId(orderInfo.getId());
            orderDetail.setSkuId(cartItem.getSkuId());
            orderDetail.setSkuName(cartItem.getSkuName());
            orderDetail.setImgUrl(cartItem.getSkuDefaultImg());
            orderDetail.setOrderPrice(cartItem.getSkuPrice());
            orderDetail.setSkuNum(cartItem.getSkuNum());
            //走到这里表示都校验过了
            orderDetail.setHasStock("1");
            orderDetail.setCreateTime(new Date());
            orderDetail.setSplitTotalAmount(new BigDecimal("0"));
            orderDetail.setSplitActivityAmount(new BigDecimal("0"));
            orderDetail.setSplitCouponAmount(new BigDecimal("0"));
            return orderDetail;
        }).collect(Collectors.toList());
        return orderDetailList;
    }

    private OrderInfo prepareOrderInfo(OrderSubmitVo orderSubmitVo) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setConsignee(orderSubmitVo.getConsignee());
        orderInfo.setConsigneeTel(orderSubmitVo.getConsigneeTel());
        //已经经过校验了,总金额一致
        List<CartItemForOrderVo> orderDetailList = orderSubmitVo.getOrderDetailList();
        BigDecimal bigDecimal = orderDetailList.stream().map((cartItemForOrderVo) -> {
            BigDecimal multiply = cartItemForOrderVo.getOrderPrice().multiply(BigDecimal.valueOf(cartItemForOrderVo.getSkuNum()));
            return multiply;
        }).reduce(BigDecimal::add).get();
        orderInfo.setTotalAmount(bigDecimal);
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        Long userId = UserAuthToUtil.getUserAuthTo().getUserId();
        orderInfo.setUserId(userId);
        orderInfo.setPaymentWay(orderSubmitVo.getPaymentWay());
        orderInfo.setDeliveryAddress(orderSubmitVo.getDeliveryAddress());
        orderInfo.setOrderComment(orderSubmitVo.getOrderComment());
        //对外交易号
        String uuId = UUID.randomUUID().toString().substring(0, 6);
        orderInfo.setOutTradeNo("GMALL-" + System.currentTimeMillis() +"-"+userId + "-" + uuId);
        //订单体:所有的商品名
        String skuNames = orderDetailList.stream().map(CartItemForOrderVo::getSkuName).reduce((a, b) -> {
            return a + ";" + b;
        }).get();
        orderInfo.setTradeBody(skuNames);
        orderInfo.setCreateTime(new Date());
        //当前时间+30分钟
        Long time = System.currentTimeMillis() + 1000 * 60 * 30;
        orderInfo.setExpireTime(new Date(time));
        //未支付状态
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
        //物流追踪号,发货后才有
        orderInfo.setTrackingNo("");
        //拆单
        orderInfo.setParentOrderId(0L);
        //订单展示图片
        orderInfo.setImgUrl(orderDetailList.get(0).getImgUrl());
        orderInfo.setOrderDetailList(Lists.newArrayList());
        orderInfo.setWareId("");
        orderInfo.setProvinceId(0L);
        orderInfo.setActivityReduceAmount(new BigDecimal("0"));
        orderInfo.setCouponAmount(new BigDecimal("0"));
        orderInfo.setOriginalTotalAmount(new BigDecimal("0"));
        //可退款日期
        orderInfo.setRefundableTime(new Date());
        orderInfo.setFeightFee(new BigDecimal("0"));
        orderInfo.setOperateTime(new Date());
//        orderInfo.setOrderDetailVoList(Lists.newArrayList());
//        orderInfo.setCouponInfo(new CouponInfo());
//        orderInfo.setId(0L);


        return orderInfo;
    }
}
